[C# 7] Visual Studio 2017 RC でC# 7の新機能を試してみた
はじめに
こんにちは!モバイルアプリサービス部の加藤潤です。
先日発表されたVisual Studio for Macが注目を集めていますが、同時に時期バージョンのVisual Studio、「Visual Studio 2017」のRC版もリリースされました。
このバージョンではC# 7の機能を試すことができるので勉強も兼ねて試してみました!
開発環境
- Windows 10 Pro
- Visual Studio Community 2017 RC
インストール
Visual Studio(以下、VS)2017 RCのインストーラーはこちらからダウンロードすることができます。
インストールもカテゴリ分けされていてだいぶわかり易くなりましたね。今回は「.NETデスクトップ開発」を選んでみました。
C# 7の新機能
タプル
こちらはVSをインストールしただけでは使えないようです。以下のように別途NuGetでSystem.ValueTuple
パッケージをインストールする必要があります。
パッケージをインストールすると、以下のようにタプルが使えるようになります。
// 明示的な型指定(メンバー名指定なし) (int, string) result = (200, "OK"); // メンバーにはItemNでアクセス可能 WriteLine($"{result.Item1},{result.Item2}"); // 200,OK // 明示的な型指定(メンバー名指定あり) (int code, string message) result = (200, "OK"); // メンバー名でアクセス可能 WriteLine($"{result.code},{result.message}"); // 200,OK
型推論も効きます。
// 型推論 var result = (code: 200, message: "OK");
引数や戻り値にも使えます。
static (int code, string message) GetResult((int, int)param) { return (400, "Bad Request"); } // 引数や戻り値にも使える var result = GetResult((1, 2)); WriteLine($"{result.code},{result.message}"); // 400,Bad Request
タプルを分解して別の変数に格納することも可能です。
// タプルの分解 var (v1, v2) = result;
ローカル関数
関数の中に関数を定義することが出来るようになりました。
下の例ではMain
関数内でのみ使えるローカル関数add
を定義しています。
static void Main(string[] args) { // ローカル関数 int add(int x, int y) => x + y; WriteLine(add(3, 5)); // 8 }
型スイッチ
is
演算子を使って型を判定すると同時にその型の変数が使えるようになりました。
object obj = "test"; if (obj is string s) { WriteLine(s); // test }
これによって、特にnull許容型で値を取得する際にスッキリ書けるようです。
int? intOrNull = 100; // C# 7以前 if (intOrNull.HasValue) { var value = intOrNull.GetValueOrDefault(); WriteLine($"value is {value}"); } // C# 7 if (intOrNull is int v) { WriteLine($"value is {v}"); }
また、switchステートメントのcaseでも型による分岐ができるようになりました。
さらにwhen
を使った条件(case guard)も記述できます。
object obj = 99; switch (obj) { case "test": WriteLine(); break; case int v when 100 < v: WriteLine($"{v} is greater than 100"); break; case int v: WriteLine(v); // ここを通る break; default: WriteLine("default"); break; }
出力変数宣言
以下のようなstructの定義があったとして、GetCoordinatesメソッドの出力変数でxとyの値を取得したい場合を考えます。
struct Point { public Point(int x, int y) { X = x; Y = y; } public int X { get; } public int Y { get; } public void GetCoordinates(out int x, out int y) { x = X; y = Y; } }
以前はout引数を受け取る前に変数宣言が必要でしたが、C# 7では引数受け取りと同時に変数の宣言ができるようになりました。
// C# 7以前 var p = new Point(100, 200); // 事前に変数の宣言が必要 int x, y; p.GetCoordinates(out x, out y); WriteLine($"({x},{y})"); // (100,200) // C# 7 var p = new Point(100, 200); p.GetCoordinates(out int x, out int y); WriteLine($"({x},{y})"); // (100,200)
型推論も使えます。
p.GetCoordinates(out var x, out var y);
その他
- 非同期メソッドの戻り値に
Task<T>
とTask
以外の型が使えるようになった - 戻り値とローカル変数でも参照渡しが使えるようになった
おわりに
C#も着実により便利に進化していますね。ScalaやF#に影響を受けているパターンマッチはまだまだ一部の実装にとどまっていますが、C# 8以降で更なる進化を遂げることと思います。
Xamarinも現状はC# 6での開発ですが、いずれC# 7が使えるようになることでしょう。
Scalaや関数型言語などの他の言語の良いところをうまく取り込んでいく姿勢が見えます。そういう意味ではだんだんと言語の垣根は無くなってきていると感じます。